Flutter 渲染流水线

对 Flutter 渲染机制,在网络上已经有诸多优秀资源,文本是我对这些优秀文章学习后的笔记。本文中的内容对这些文章多有引用,在此统一声明。相关好文章如下:


Step1:以 setState 触发帧调度

开发者调用 setState 触发状态更新:

// State
@protected
void setState(VoidCallback fn) {
  // ...
  final Object? result = fn() as dynamic;
  // ...
  _element!.markNeedsBuild();
}	

调用 element 标脏:

// Element
void markNeedsBuild() {
  // ...
  // 已经标过的不会重复标
  if (dirty) return;
  _dirty = true;
  owner!.scheduleBuildFor(this);
}

来到 BuildOwner

// BuildOwner
void scheduleBuildFor(Element element) {
  //...
  // 如果已经在列表中,直接返回
  if (element._inDirtyList) {
    // ...
    // 用于标记在构建过程中是否有更多的元素变为"dirty"(需要重新构建),从而需要重新对`_dirtyElements`进行排序。
    _dirtyElementsNeedsResorting = true;
    return;
  }
  // onBuildScheduled 方法非常关键
  if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
    _scheduledFlushDirtyElements = true;
    onBuildScheduled!();
  }
  // 添加到脏的列表中
  _dirtyElements.add(element);
  element._inDirtyList = true;
  // ...
}

WidgetsBinding 关联了 onBuildScheduled,当 onBuildScheduled 调用时,实际调用的是 WidgetsBinding 的 _handleBuildScheduled

void _handleBuildScheduled() {
  ensureVisualUpdate();
}

ensureVisualUpdate 将会调度一个新的帧:

// SchedulerBinding
void ensureVisualUpdate() {
  switch (schedulerPhase) {
    case SchedulerPhase.idle:
    case SchedulerPhase.postFrameCallbacks:
      scheduleFrame();
      return;
    case SchedulerPhase.transientCallbacks:
    case SchedulerPhase.midFrameMicrotasks:
    case SchedulerPhase.persistentCallbacks:
      return;
  }
}

// SchedulerBinding
void scheduleFrame() {
  if (_hasScheduledFrame || !framesEnabled)
    return;
  ensureFrameCallbacksRegistered();
  window.scheduleFrame();
  _hasScheduledFrame = true;
}

接下来从 Flutter Framework 中来到 Flutter Engine:

// window.dart
void scheduleFrame() => platformDispatcher.scheduleFrame();

// platformDispatcher
void scheduleFrame() native 'PlatformConfiguration_scheduleFrame';

来到 platform_configuration.cc 的 ScheduleFrame:

void ScheduleFrame(Dart_NativeArguments args) {
  UIDartState::ThrowIfUIOperationsProhibited();
  UIDartState::Current()->platform_configuration()->client()->ScheduleFrame();
}

client 实际上是 RuntimeController:

// RuntimeController
void RuntimeController::ScheduleFrame() {
  client_.ScheduleFrame();
}

调用到 Engine 的 ScheduleFrame:

// Engine
void ScheduleFrame() { ScheduleFrame(true); }

// Engine
void Engine::ScheduleFrame(bool regenerate_layer_tree) {
  StartAnimatorIfPossible();
  animator_->RequestFrame(regenerate_layer_tree);
}

// Engine
void Engine::StartAnimatorIfPossible() {
  if (activity_running_ && have_surface_) {
    animator_->Start();
  }
}

Step2:ASYNC 信号注册

其中,animator_ 会注册 ASYNC 信号。

// Animator
void Animator::Start() {
  if (!paused_) {
    return;
  }

  paused_ = false;
  RequestFrame();
}

// Animator
void Animator::RequestFrame(bool regenerate_layer_tree) {
  //...
  task_runners_.GetUITaskRunner()->PostTask(
      [self = weak_factory_.GetWeakPtr(),
       frame_request_number = frame_request_number_]() {
        if (!self) {
          return;
        }
        // 等待 ASYNC 信号
        self->AwaitVSync();
      });
  frame_scheduled_ = true;
}

// Animator
void Animator::AwaitVSync() {
  waiter_->AsyncWaitForVsync(
      [self = weak_factory_.GetWeakPtr()](
          std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
        // ASYNC 信号回来
        if (self) {
          if (self->CanReuseLastLayerTree()) {
            self->DrawLastLayerTreemove(frame_timings_recorder);
          } else {
            // 开始新的一帧
            self->BeginFramemove(frame_timings_recorder);
          }
        }
      });
  // ...
}

Step3:BeginFrame 开启新的一帧

// Animator
void Animator::BeginFrame(
    std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
  // ...
  {
    uint64_t frame_number = frame_timings_recorder_->GetFrameNumber();
    delegate_.OnAnimatorBeginFrame(frame_target_time, frame_number);
  }
}

// Shell
void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_target_time,
                                 uint64_t frame_number) {
  // ...
  if (engine_) {
    engine_->BeginFrame(frame_target_time, frame_number);
  }
}

// Engine
void Engine::BeginFrameTimePoint frame_time, uint64_t frame_number {
  TRACE_EVENT0("flutter", "Engine::BeginFrame");
  runtime_controller_->BeginFrame(frame_time, frame_number);
}

// RuntimeController
bool RuntimeController::BeginFrame(fml::TimePoint frame_time,
                                   uint64_t frame_number) {
  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
    platform_configuration->BeginFrame(frame_time, frame_number);
    return true;
  }

  return false;
}

// PlatformConfiguration
void PlatformConfiguration::BeginFrame(fml::TimePoint frameTime,
                                       uint64_t frame_number) {
  // 调用 dart 中的 _window.onBeginFrame
  std::shared_ptr<tonic::DartState> dart_state =
      begin_frame_.dart_state().lock();
  if (!dart_state) {
    return;
  }
  tonic::DartState::Scope scope(dart_state);
  // 刷新 microTasks
  UIDartState::Current()->FlushMicrotasksNow();
  // 调用 _drawFrame
  tonic::LogIfErrorDartInvokeVoid(draw_frame_.Get());
}

在 PlatformConfiguration::BeginFrame 中,分别调用了两个 Dart 方法:

这两方法的绑定过程:

// hooks.dart
@pragma('vm:entry-point')
void _beginFrame(int microseconds, int frameNumber) {
  PlatformDispatcher.instance._beginFrame(microseconds);
  PlatformDispatcher.instance._updateFrameData(frameNumber);
}

// hooks.dart
@pragma('vm:entry-point')
void _drawFrame() {
  PlatformDispatcher.instance._drawFrame();
}

// platform_dispatcher.dart
FrameCallback? get onBeginFrame => _onBeginFrame;
FrameCallback? _onBeginFrame;
Zone _onBeginFrameZone = Zone.root;
set onBeginFrame(FrameCallback? callback) {
  _onBeginFrame = callback;
  _onBeginFrameZone = Zone.current;
}

void _beginFrame(int microseconds) {
  _invoke1<Duration>(
    onBeginFrame,
    _onBeginFrameZone,
    Duration(microseconds: microseconds),
  );
}

// platform_dispatcher.dart
VoidCallback? get onDrawFrame => _onDrawFrame;
VoidCallback? _onDrawFrame;
Zone _onDrawFrameZone = Zone.root;
set onDrawFrame(VoidCallback? callback) {
  _onDrawFrame = callback;
  _onDrawFrameZone = Zone.current;
}

// Called from the engine, via hooks.dart
void _drawFrame() {
  _invoke(onDrawFrame, _onDrawFrameZone);
}

之后来到 Framework 侧:

// ScheduleBinding
@protected
void ensureFrameCallbacksRegistered() {
  window.onBeginFrame ??= _handleBeginFrame;
  window.onDrawFrame ??= _handleDrawFrame;
}

Step3-1:_handleBeginFrame

这一步处理临时性任务,比如动画的计算。对应的遍历执行 transientCallbacks 毁掉集合。

// ScheduleBinding
void _handleBeginFrame(Duration rawTimeStamp) {
  // ...
  handleBeginFrame(rawTimeStamp);
}

// ScheduleBinding
void handleBeginFrame(Duration? rawTimeStamp) {
  //...
  try {
    // 执行基于 Ticker 的动画任务更新回调
    _schedulerPhase = SchedulerPhase.transientCallbacks;
    final Map<int, _FrameCallbackEntry> callbacks = _transientCallbacks;
    _transientCallbacks = <int, _FrameCallbackEntry>{};
    callbacks.forEach((int id, _FrameCallbackEntry callbackEntry) {
      if (!_removedIds.contains(id))
        _invokeFrameCallback(callbackEntry.callback, _currentFrameTimeStamp!, callbackEntry.debugStack);
    });
    _removedIds.clear();
  } finally {
    // 状态流转:后续由 C++ 调度 microTasks
    _schedulerPhase = SchedulerPhase.midFrameMicrotasks;
  }
}

Step3-2:_handleDrawFrame

从代码看,这一步与上一步差不多,遍历执行 persistentCallbacks 集合。但这一步里面大有乾坤,Flutter Widget Tree 的 Build、Layout、Paint 都是在其中完成的。

// ScheduleBinding
void _handleDrawFrame() {
  // ...
  handleDrawFrame();
}

// ScheduleBinding
void handleDrawFrame() {
  try {
    // PERSISTENT FRAME CALLBACKS
    // 这些回调是绘制一帧所必须的,如 build、layout、paint
    _schedulerPhase = SchedulerPhase.persistentCallbacks;
    for (final FrameCallback callback in _persistentCallbacks)
      _invokeFrameCallback(callback, _currentFrameTimeStamp!);

    // POST-FRAME CALLBACKS
    // PostFrameCallback 的调用时机
    _schedulerPhase = SchedulerPhase.postFrameCallbacks;
    final List<FrameCallback> localPostFrameCallbacks =
        List<FrameCallback>.of(_postFrameCallbacks);
    _postFrameCallbacks.clear();
    for (final FrameCallback callback in localPostFrameCallbacks)
      _invokeFrameCallback(callback, _currentFrameTimeStamp!);
  } finally {
    // 一帧调度完成,进入空闲状态
    _schedulerPhase = SchedulerPhase.idle;
  }
}

在 Framework 中搜索调用 addPersistentFrameCallback 的地方有很多,但其中有一位特别的重量级选手——RendererBinding,Flutter Widget Tree 的 Build、Layout、Paint 都是在其中完成的:

// ScheduleBinding
void addPersistentFrameCallback(FrameCallback callback) {
  _persistentCallbacks.add(callback);
}

// RendererBinding
@override
void initInstances() {
  super.initInstances();
  // ...
  addPersistentFrameCallback(_handlePersistentFrameCallback);
  // ...
}

// RendererBinding
void _handlePersistentFrameCallback(Duration timeStamp) {
  drawFrame();
  _scheduleMouseTrackerUpdate();
}

Step4:组件树构建

drawFrame 方法,是组件树的构建方法,将会触发 Build、Layout、Paint。需要注意的是,Bindings 采用 mixin 机制,drawFrame 将由多个 Bindings 共同协作完成:

// WidgetsBinding
@override
void drawFrame() {
  // ...
  if (renderViewElement != null)
    buildOwner!.buildScope(renderViewElement!);
  super.drawFrame();
  buildOwner!.finalizeTree();
}

// RendererBinding
@protected
void drawFrame() {
  assert(renderView != null);
  pipelineOwner.flushLayout();
  pipelineOwner.flushCompositingBits();
  pipelineOwner.flushPaint();
  if (sendFramesToEngine) {
    renderView.compositeFrame(); // this sends the bits to the GPU
    pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
    _firstFrameSent = true;
  }
}

整体构建顺序为:

一共 5 步,下面分别介绍。


Step4-1:Build 阶段

在 Step 中,我们通过 setState 对 element 标脏。在 buildOwner!.buildScope 中会对他们进行统一处理,按照深度排序的顺序 rebuild。所谓深度排序,先让父组件 rebuild,再让子组件 rebuild,防止子组件重复构建。核心代码:

// BuildOwner
void buildScope(Element context, [ VoidCallback? callback ]) {
  if (callback == null && _dirtyElements.isEmpty)
    return;
  try {
    if (callback != null) {
      callback();
    }
    
    _dirtyElements.sort(Element._sort);
    int dirtyCount = _dirtyElements.length;
    int index = 0;
    while (index < dirtyCount) {
      final Element element = _dirtyElements[index];
      try {
        element.rebuild();
      } catch (e, stack) {/*...*/ }
      index += 1;
    }
  } finally {
    for (final Element element in _dirtyElements) {
      element._inDirtyList = false;
    }
    _dirtyElements.clear();
  }
}

// Element
void rebuild() {
  if (_lifecycleState != _ElementLifecycle.active || !_dirty)
    return;
  // 抽象方法,由具体 Element 实现
  performRebuild();
}

// ComponentElement
void performRebuild() {
  Widget? built;
  try {
    built = build();
  } catch (e, stack) { /*...*/} 
    finally {/*...*/}
  try {
    _child = updateChild(_child, built, slot);
  } catch (e, stack) {
    // ...
    _child = updateChild(null, built, slot);
  }
}


Step4-2:Layout 阶段

对所有标记为 dirty 的 Render Object 重新计算布局。

// PipelineOwner
void flushLayout() {
  try {
    while (_nodesNeedingLayout.isNotEmpty) {
      final List<RenderObject> dirtyNodes = _nodesNeedingLayout;
      _nodesNeedingLayout = <RenderObject>[];
      for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => a.depth - b.depth)) {
        if (node._needsLayout && node.owner == this)
          node._layoutWithoutResize();
      }
    }
  } finally {}
}

Step4-3:刷新合成位

// PipelineOwner
void flushCompositingBits() {
  _nodesNeedingCompositingBitsUpdate.sort((RenderObject a, RenderObject b) => a.depth - b.depth);
  for (final RenderObject node in _nodesNeedingCompositingBitsUpdate) {
    if (node._needsCompositingBitsUpdate && node.owner == this)
      node._updateCompositingBits();
  }
  _nodesNeedingCompositingBitsUpdate.clear();
}

Step4-4:绘制

根据 Render Object 生成 Display LIst。这一步会调用 Render Object 的 paint 方法,生成 Layer。

// PipelineOwner
void flushPaint() {
  try {
    final List<RenderObject> dirtyNodes = _nodesNeedingPaint;
    _nodesNeedingPaint = <RenderObject>[];
    // Sort the dirty nodes in reverse order (deepest first).
    for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => b.depth - a.depth)) {
      assert(node._layerHandle.layer != null);
      if (node._needsPaint && node.owner == this) {
        if (node._layerHandle.layer!.attached) {
          PaintingContext.repaintCompositedChild(node);
        } else {
          node._skippedPaintingOnLayer();
        }
      }
    }

  } finally {}
}

// PaintingContext
// Render Object 重绘
static void repaintCompositedChild(RenderObject child, { bool debugAlsoPaintedParent = false }) {
  assert(child._needsPaint);
  _repaintCompositedChild(
    child,
    debugAlsoPaintedParent: debugAlsoPaintedParent,
  );
}

// PaintingContext
static void _repaintCompositedChild(
  RenderObject child, {
  bool debugAlsoPaintedParent = false,
  PaintingContext? childContext,
}) {
  OffsetLayer? childLayer = child._layerHandle.layer as OffsetLayer?;
  if (childLayer == null) {
    // Not using the `layer` setter because the setter asserts that we not
    // replace the layer for repaint boundaries. That assertion does not
    // apply here because this is exactly the place designed to create a
    // layer for repaint boundaries.
    final OffsetLayer layer = OffsetLayer();
    child._layerHandle.layer = childLayer = layer;
  } else {
    childLayer.removeAllChildren();
  }
  childContext ??= PaintingContext(childLayer, child.paintBounds);
  child._paintWithContext(childContext, Offset.zero);

  // Double-check that the paint method did not replace the layer (the first
  // check is done in the [layer] setter itself).
  childContext.stopRecordingIfNeeded();
}

// RenderObject
void _paintWithContext(PaintingContext context, Offset offset) {
  // If we still need layout, then that means that we were skipped in the
  // layout phase and therefore don't need painting. We might not know that
  // yet (that is, our layer might not have been detached yet), because the
  // same node that skipped us in layout is above us in the tree (obviously)
  // and therefore may not have had a chance to paint yet (since the tree
  // paints in reverse order). In particular this will happen if they have
  // a different layer, because there's a repaint boundary between us.
  if (_needsLayout)
    return;
  _needsPaint = false;
  try {
    paint(context, offset);
  } catch (e, stack) {
    _debugReportException('paint', e, stack);
  }
}

Step5:帧合成

绘制完成后,继续 RendererBinding.drawFrame 中的流程,接下来该帧合成:

// RenderView
void compositeFrame() {
  try {
    // 将 Layer 转换为 Scene
    // 在 Dart 和 C++ 层都创建对应的 Builder 和 Scene
    final ui.SceneBuilder builder = ui.SceneBuilder();
    final ui.Scene scene = layer!.buildScene(builder);

    // 将 Scene 发送给 GPU 线程
    _window.render(scene);
    scene.dispose();
  } finally {}
}

Step6:提交 GPU 线程

// window.dart(Framework)
void render(Scene scene) => _render(scene, this);
void _render(Scene scene, FlutterView view) native 'PlatformConfiguration_render';

// PlatformConfiguration(Engine)
void Render(Dart_NativeArguments args) {
  UIDartState::ThrowIfUIOperationsProhibited();
  Dart_Handle exception = nullptr;
  Scene* scene =
      tonic::DartConverter<Scene*>::FromArguments(args, 1, exception);
  UIDartState::Current()->platform_configuration()->client()->Render(scene);
}

// Engine.cc
void Engine::RenderLayerTree> layer_tree {
  if (!layer_tree) {
    return;
  }

  // Ensure frame dimensions are sane.
  if (layer_tree->frame_size().isEmpty() ||
      layer_tree->device_pixel_ratio() <= 0.0f) {
    return;
  }

  animator_->Rendermove(layer_tree);
}

// animator.cc
void Animator::RenderLayerTree> layer_tree {

  // Commit the pending continuation.
  bool result = producer_continuation_.Completemove(layer_tree);
 
  // shell
  delegate_.OnAnimatorDraw(layer_tree_pipeline_,
                           std::move(frame_timings_recorder_));
}

// shell.cc
void Shell::OnAnimatorDraw(
    std::shared_ptr<Pipeline<flutter::LayerTree>> pipeline,
    std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {

  auto discard_callback = [this]LayerTree& tree {
    std::scoped_lock<std::mutex> lock(resize_mutex_);
    return !expected_frame_size_.isEmpty() &&
           tree.frame_size() != expected_frame_size_;
  };

  // 切换到 GPU 线程
  task_runners_.GetRasterTaskRunner()->PostTask(fml::MakeCopyable(
      [&waiting_for_first_frame = waiting_for_first_frame_,
       &waiting_for_first_frame_condition = waiting_for_first_frame_condition_,
       rasterizer = rasterizer_->GetWeakPtr(),
       weak_pipeline = std::weak_ptr<Pipeline<LayerTree>>(pipeline),
       discard_callback = std::move(discard_callback),
       frame_timings_recorder = std::move(frame_timings_recorder)]() mutable {
        if (rasterizer) {
          // 线程锁
          std::shared_ptr<Pipeline<LayerTree>> pipeline = weak_pipeline.lock();
          if (pipeline) {
            // GPU 绘制
            rasterizer->Drawmove(frame_timings_recorder,
                             std::move(pipeline), std::move(discard_callback));
          }

          if (waiting_for_first_frame.load()) {
            waiting_for_first_frame.store(false);
            waiting_for_first_frame_condition.notify_all();
          }
        }
      }));
}

Step7 rasterizer 绘制

// rasterizer.cc
RasterStatus Rasterizer::Draw(
    std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder,
    std::shared_ptr<Pipeline<flutter::LayerTree>> pipeline,
    LayerTreeDiscardCallback discard_callback) {
  // 如果开启了线程合并,这一步已经完成了
  if (raster_thread_merger_ &&
      !raster_thread_merger_->IsOnRasterizingThread()) {
    // we yield and let this frame be serviced on the right thread.
    return RasterStatus::kYielded;
  }

  std::unique_ptr<FrameTimingsRecorder> resubmit_recorder =
      frame_timings_recorder->CloneUntil(
          FrameTimingsRecorder::State::kBuildEnd);

  RasterStatus raster_status = RasterStatus::kFailed;
  Pipeline<flutter::LayerTree>::Consumer consumer =
      [&]unique_ptr<LayerTree> layer_tree {
        if (discard_callback(*layer_tree.get())) {
          raster_status = RasterStatus::kDiscarded;
        } else {
          // 绘制
          raster_status =
              DoDrawmove(frame_timings_recorder), std::move(layer_tree);
        }
      };

  PipelineConsumeResult consume_result = pipeline->Consume(consumer);
  
  //...

  if (surface_ && external_view_embedder_) {
    external_view_embedder_->EndFrame(should_resubmit_frame,
                                      raster_thread_merger_);
  }

  return raster_status;
}

// rasterizer.cc
RasterStatus Rasterizer::DoDraw(
    std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder,
    std::unique_ptr<flutter::LayerTree> layer_tree) {

  PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess();
  persistent_cache->ResetStoredNewShaders();

  // 向 OpenGL Surface 绘制
  RasterStatus raster_status =
      DrawToSurface(*frame_timings_recorder, *layer_tree);

  //...

  // TODO(liyuqian): in Fuchsia, the rasterization doesn't finish when
  // Rasterizer::DoDraw finishes. Future work is needed to adapt the timestamp
  // for Fuchsia to capture SceneUpdateContext::ExecutePaintTasks.
  delegate_.OnFrameRasterized(frame_timings_recorder->GetRecordedTime());

  // Pipeline pressure is applied from a couple of places:
  // rasterizer: When there are more items as of the time of Consume.
  // animator (via shell): Frame gets produces every vsync.
  // Enqueing here is to account for the following scenario:
  // T = 1
  //  - one item (A) in the pipeline
  //  - rasterizer starts (and merges the threads)
  //  - pipeline consume result says no items to process
  // T = 2
  //  - animator produces (B) to the pipeline
  //  - applies pipeline pressure via platform thread.
  // T = 3
  //   - rasterizes finished (and un-merges the threads)
  //   - |Draw| for B yields as its on the wrong thread.
  // This enqueue ensures that we attempt to consume from the right
  // thread one more time after un-merge.
  if (raster_thread_merger_) {
    if (raster_thread_merger_->DecrementLease() ==
        fml::RasterThreadStatus::kUnmergedNow) {
      return RasterStatus::kEnqueuePipeline;
    }
  }

  return raster_status;
}

Step7-1 Surface 绘制

// Rasterizer::DrawToSurface
RasterStatus Rasterizer::DrawToSurface(
    FrameTimingsRecorder& frame_timings_recorder,
    flutter::LayerTree& layer_tree) {
  RasterStatus raster_status;
  if (surface_->AllowsDrawingWhenGpuDisabled()) {
    raster_status = DrawToSurfaceUnsafe(frame_timings_recorder, layer_tree);
  } else {
    delegate_.GetIsGpuDisabledSyncSwitch()->Execute(
        fml::SyncSwitch::Handlers()
            .SetIfTrue([&] { raster_status = RasterStatus::kDiscarded; })
            .SetIfFalse([&] {
              raster_status =
                  DrawToSurfaceUnsafe(frame_timings_recorder, layer_tree);
            }));
  }

  return raster_status;
}

// Rasterizer::DrawToSurfaceUnsafe
RasterStatus Rasterizer::DrawToSurfaceUnsafe(
    FrameTimingsRecorder& frame_timings_recorder,
    flutter::LayerTree& layer_tree) {

  SkCanvas* embedder_root_canvas = nullptr;
  // Hybrid Composition 下,PlatformView 的帧绘制是从这里开始的
  if (external_view_embedder_) {
    external_view_embedder_->BeginFrame(
        layer_tree.frame_size(), surface_->GetContext(),
        layer_tree.device_pixel_ratio(), raster_thread_merger_);
    embedder_root_canvas = external_view_embedder_->GetRootCanvas();
  }

  // On Android, the external view embedder deletes surfaces in `BeginFrame`.
  //
  // Deleting a surface also clears the GL context. Therefore, acquire the
  // frame after calling `BeginFrame` as this operation resets the GL context.
  auto frame = surface_->AcquireFrame(layer_tree.frame_size());
  if (frame == nullptr) {
    return RasterStatus::kFailed;
  }

  // If the external view embedder has specified an optional root surface, the
  // root surface transformation is set by the embedder instead of
  // having to apply it here.
  SkMatrix root_surface_transformation =
      embedder_root_canvas ? SkMatrix{} : surface_->GetRootTransformation();

  auto root_surface_canvas =
      embedder_root_canvas ? embedder_root_canvas : frame->SkiaCanvas();

  // 帧合成器
  auto compositor_frame = compositor_context_->AcquireFrame(
      surface_->GetContext(),         // skia GrContext
      root_surface_canvas,            // root surface canvas
      external_view_embedder_.get(),  // external view embedder
      root_surface_transformation,    // root surface transformation
      true,                           // instrumentation enabled
      frame->framebuffer_info()
          .supports_readback,  // surface supports pixel reads
      raster_thread_merger_    // thread merger
  );
  if (compositor_frame) {
    compositor_context_->raster_cache().PrepareNewFrame();

    // Disable partial repaint if external_view_embedder_ SubmitFrame is
    // involved - ExternalViewEmbedder unconditionally clears the entire
    // surface and also partial repaint with platform view present is something
    // that still need to be figured out.
    bool disable_partial_repaint =
        external_view_embedder_ &&
        (!raster_thread_merger_ || raster_thread_merger_->IsMerged());

    FrameDamage damage;
    if (!disable_partial_repaint && frame->framebuffer_info().existing_damage) {
      damage.SetPreviousLayerTree(last_layer_tree_.get());
      damage.AddAdditonalDamage(*frame->framebuffer_info().existing_damage);
    }

    // 光栅化
    RasterStatus raster_status =
        compositor_frame->Raster(layer_tree, false, &damage);
    if (raster_status == RasterStatus::kFailed ||
        raster_status == RasterStatus::kSkipAndRetry) {
      return raster_status;
    }

    SurfaceFrame::SubmitInfo submit_info;
    submit_info.frame_damage = damage.GetFrameDamage();
    submit_info.buffer_damage = damage.GetBufferDamage();

    frame->set_submit_info(submit_info);

    // 上屏!
    if (external_view_embedder_ &&
        (!raster_thread_merger_ || raster_thread_merger_->IsMerged())) {
      FML_DCHECK(!frame->IsSubmitted());
      external_view_embedder_->SubmitFrame(surface_->GetContext(),
                                           std::move(frame));
    } else {
      frame->Submit();
    }

    compositor_context_->raster_cache().CleanupAfterFrame();
    frame_timings_recorder.RecordRasterEnd(
        &compositor_context_->raster_cache());
    FireNextFrameCallbackIfPresent();

    if (surface_->GetContext()) {
      TRACE_EVENT0("flutter", "PerformDeferredSkiaCleanup");
      surface_->GetContext()->performDeferredCleanup(kSkiaCleanupExpiration);
    }

    return raster_status;
  }

  return RasterStatus::kFailed;
}

在上屏前,有一个很重要的步骤 compositor_frame->Raster 光栅化。


Step7-2 光栅化

// RasterStatus CompositorContext::ScopedFrame
RasterStatus CompositorContext::ScopedFrame::Raster(
    flutter::LayerTree& layer_tree,
    bool ignore_raster_cache,
    FrameDamage* frame_damage) {

  std::optional<SkRect> clip_rect =
      frame_damage ? frame_damage->ComputeClipRect(layer_tree) : std::nullopt;

  bool root_needs_readback = layer_tree.Preroll(
      *this, ignore_raster_cache, clip_rect ? *clip_rect : kGiantRect);
  bool needs_save_layer = root_needs_readback && !surface_supports_readback();
  PostPrerollResult post_preroll_result = PostPrerollResult::kSuccess;
  if (view_embedder_ && raster_thread_merger_) {
    post_preroll_result =
        view_embedder_->PostPrerollAction(raster_thread_merger_);
  }

  if (post_preroll_result == PostPrerollResult::kResubmitFrame) {
    return RasterStatus::kResubmit;
  }
  if (post_preroll_result == PostPrerollResult::kSkipAndRetryFrame) {
    return RasterStatus::kSkipAndRetry;
  }

  SkAutoCanvasRestore restore(canvas(), clip_rect.has_value());

  // Clearing canvas after preroll reduces one render target switch when preroll
  // paints some raster cache.
  // ...
  // 遍历 LayerTree,光栅化
  layer_tree.Paint(*this, ignore_raster_cache);
  if (canvas() && needs_save_layer) {
    canvas()->restore();
  }
  return RasterStatus::kSuccess;
}

其中,在有 Hybrid Composition 平台视图的场景下,还有两步:

  1. layer_tree.Preroll
  2. view_embedder_->PostPrerollAction

总结

至此 Flutter 的一帧绘制完成。

Flutter 渲染流水线梳理完毕。


本文作者:Maeiee

本文链接:Flutter 渲染流水线

版权声明:如无特别声明,本文即为原创文章,版权归 Maeiee 所有,未经允许不得转载!


喜欢我文章的朋友请随缘打赏,鼓励我创作更多更好的作品!